home *** CD-ROM | disk | FTP | other *** search
- /*
- * "ls" for anything, including MiNT.
- *
- * By Allan Pratt, Atari Corp. (atari!apratt).
- * Attribute suggestions and code from entropy@wookumz.ai.mit.edu 3/91.
- *
- * There's still one FIXME: "ls *.c" looks terrible, with each filename
- * alone on a line, and double-spaced. The top-level arguments should be
- * gathered into a list, and that list sorted as a single "ls." Then
- * if any of those names are subdirectories, you get a double linefeed,
- * then the name that generated the sublist, then the sublist.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <osbind.h>
- #include <string.h>
- #include <ctype.h>
-
- #ifdef __GNUC__
- /* minimal stuff */
-
- #include <minimal.h>
- #include <stdarg.h>
-
- int printf(const char *fmt,...)
- {
- va_list args;
- char buf[128];
- va_start(args,fmt);
- vsprintf(buf,fmt,args);
- Cconws(buf);
- return 0;
- }
-
- #undef putchar
- #define putchar(c) Cconout(c)
- #endif
-
- #define TRUE 1
- #define FALSE 0
-
- #define DRV_CHAR ':'
- #define PATH_CHAR '\\'
-
- /* is_root: TRUE for d: and d:\ */
- #define is_root(s) ((s)[1] == ':' && (!(s)[2] || ((s)[2] == '\\' && !(s)[3])))
-
- /* is_dots: TRUE for . and .. */
- #define is_dots(s) (*(s) == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2])))
-
- extern char *syserr(long);
-
- /* these all initialize to zero */
- struct _dta *dtas;
- int nfiles;
- int nalloc;
-
- /* so do these */
- int lflag, fflag, aflag, rflag, tflag, dflag;
-
- unsigned short too_long_ago;
-
- char Monthname[] = " JanFebMarAprMayJunJulAugSepOctNovDec";
-
- int cmpname(const struct _dta *a, const struct _dta *b)
- {
- return strcmp(a->dta_name,b->dta_name);
- }
-
- int cmptrue(const struct _dta *a, const struct _dta *b)
- {
- char *aname, *bname;
-
- aname = *(char **)a->dta_name;
- bname = *(char **)b->dta_name;
- return strcmp(aname,bname);
- }
-
- int cmptime(const struct _dta *a, const struct _dta *b)
- {
- unsigned long datime1, datime2;
- datime1 = ((unsigned long)a->dta_date) << 16 |
- (unsigned long)a->dta_time;
- datime2 = ((unsigned long)b->dta_date) << 16 |
- (unsigned long)b->dta_time;
- if (datime1 > datime2) return -1;
- else if (datime1 == datime2) return 0;
- else return 1;
- }
-
- void
- add_file(struct _dta *dta)
- {
- if (dtas == NULL) {
- dtas = malloc(10 * sizeof(struct _dta));
- nalloc = 10;
- nfiles = 0;
- }
- else if (nalloc == nfiles) {
- nalloc += 10;
- if ((dtas = realloc(dtas,nalloc * sizeof(struct _dta))) == NULL) {
- printf("Out of memory\r\n");
- Pterm(1);
- }
- }
- dtas[nfiles] = *dta;
- nfiles++;
- }
-
- void
- add_named_file(struct _dta *dta, const char *truename)
- {
- if (dtas == NULL) {
- dtas = malloc(10 * sizeof(struct _dta));
- nalloc = 10;
- nfiles = 0;
- }
- else if (nalloc == nfiles) {
- nalloc += 10;
- if ((dtas = realloc(dtas,nalloc * sizeof(struct _dta))) == NULL) {
- printf("Out of memory\r\n");
- Pterm(1);
- }
- }
- *(const char **)dta->dta_name = truename;
- dtas[nfiles] = *dta;
- nfiles++;
- }
-
- void
- downcase(char *s)
- {
- while (*s) {
- if (isupper(*s)) *s = tolower(*s);
- s++;
- }
- }
-
- /* GTP added for New Desktop -- GEM Takes Parameters */
-
- char *suffixes[] = { ".ttp", ".prg", ".tos", ".app", ".gtp" };
- #define NSUFFIXES (sizeof(suffixes) / sizeof(char *))
-
- inline int
- isexec(char *s)
- {
- int i;
- for (i = NSUFFIXES; --i >= 0; ) {
- if (strstr(s,suffixes[i])) return 1;
- }
- return 0;
- }
-
- char *
- str_attrib(int att, int exec)
- {
- static char str[9];
-
- strcpy(str, "-r------");
-
- if (att & 0x10)
- str[0] = 'd';
- if (!(att & 0x01))
- str[2] = 'w';
- if (exec)
- str[3] = 'x';
- if (att & 0x20)
- str[4] = 'a';
- if (att & 0x02)
- str[5] = 'h';
- if (att & 0x04)
- str[6] = 's';
- if (att & 0x08)
- str[7] = 'v';
- return (str);
- }
-
- /*
- * showlist: take the dtas array (size is nfiles), sort it based
- * on tflag, and output based on lflag. Then free the dtas array
- * and reinitialize the globals controlling it.
- *
- * If the argument truenames is true, and you're sorting by name,
- * the 'name' field is a string pointer, not a string.
- */
-
- void
- showlist(int truenames)
- {
- int (*cmpfn)(const void *,const void *);
- int i, j, k, nrows;
- struct _dta *s;
- int exec;
- char last_char;
- char *nameptr;
-
- /* I hate this messy cast... */
- if (tflag) {
- cmpfn = (int (*)(const void *,const void *))cmptime;
- }
- else if (truenames) {
- cmpfn = (int (*)(const void *,const void *))cmptrue;
- }
- else {
- cmpfn = (int (*)(const void *,const void *))cmpname;
- }
-
- qsort(dtas,(size_t)nfiles,sizeof(struct _dta),cmpfn);
-
- if (lflag) {
- for (i = 0, s = dtas; i < nfiles; s++, i++) {
- nameptr = (truenames ? *(char **)s->dta_name : s->dta_name);
- exec = isexec(nameptr);
- if (!fflag) last_char = ' ';
- else if (s->dta_attribute & 0x10) last_char = '\\';
- else if (exec) last_char = '*';
- else last_char = ' ';
-
- if (lflag > 1) {
- /*
- * drwxahsv aa --size-- yy/mm/dd hh:mm:ss name*
- */
- printf("%s %02x %8ld %02d/%02d/%02d %02d:%02d:%02d %s%c\r\n",
- str_attrib(s->dta_attribute,exec),
- s->dta_attribute,
- s->dta_size,
- (s->dta_date >> 9) + 80,
- (s->dta_date >> 5) & 0xf,
- (s->dta_date) & 0x1f,
-
- (s->dta_time >> 11),
- (s->dta_time >> 5) & 0x3f,
- (s->dta_time & 0x1f),
- nameptr,
- last_char);
- }
- else {
-
- /*
- * drwxahsv --size-- Mon dy hh:mm name*
- * or drwxahsv --size-- Mon dy year name* if date is >~8mos old
- */
-
- if (s->dta_date >= too_long_ago) {
- /* recent form, includes in the future! */
-
- printf("%s %8ld %.3s %2d %02d:%02d %s%c\r\n",
- str_attrib(s->dta_attribute,exec),
- s->dta_size,
- &Monthname[((s->dta_date >> 5) & 0xf)*3],
- (s->dta_date) & 0x1f,
-
- (s->dta_time >> 11),
- (s->dta_time >> 5) & 0x3f,
-
- nameptr,
- last_char);
- }
- else {
- /* old form */
- printf("%s %8ld %.3s %2d %4d %s%c\r\n",
- str_attrib(s->dta_attribute,exec),
- s->dta_size,
- &Monthname[((s->dta_date >> 5) & 0xf)*3],
- (s->dta_date) & 0x1f,
- (s->dta_date >> 9) + 1980,
-
- nameptr,
- last_char);
- }
- }
- }
- }
- else {
-
- #define NCOLS 5
-
- /* not lflag: output in 5-column format */
- nrows = (nfiles + (NCOLS-1)) / NCOLS;
- for (i = 0; i < nrows; i++) {
- s = &dtas[i];
- for (j = 0; j < NCOLS; j++, s += nrows) {
- if (s >= &dtas[nfiles]) {
- printf("\r\n");
- break;
- }
-
- nameptr = (truenames ? *(char **)s->dta_name : s->dta_name);
- printf("%s",nameptr);
- k = strlen(nameptr);
- if (fflag) {
- if (s->dta_attribute & 0x10) {
- putchar('\\');
- k++;
- }
- else if (isexec(nameptr)) {
- putchar('*');
- k++;
- }
- }
- /* don't output tab(s) after the last name on a line */
- if (j < (NCOLS-1)) {
- if (k<8) putchar('\t');
- putchar('\t');
- }
- else printf("\r\n");
- }
- }
- }
-
- if (dtas) {
- free(dtas);
- dtas = NULL;
- nalloc = 0;
- nfiles = 0;
- }
- }
-
- void
- do_dir(const char *name) {
- char buf[128]; /* requested path ends up here */
- char *temp;
- struct _dta *odta = (struct _dta *)Fgetdta();
- struct _dta dta;
- char *p;
- int n;
- long e;
-
- strcpy(buf,name);
- temp = buf;
- while (*temp) temp++;
-
- /*
- * Find the file. If it turns out to be a directory, add "\*.*" to it.
- */
-
- (void)Fsetdta(&dta);
-
- if ((e = Fsfirst(buf,-1)) < 0) {
- /* failed. Might be d: or d:\ */
- if (is_root(buf)) {
- /* OK, no -d and it's d: or d:\ -- tack on *.* and try again */
- strcpy(temp,"*.*");
- }
- else {
- printf("%s: %s\r\n",buf,syserr(e));
- goto reallydone;
- }
- }
- else {
- /* found the file: is it a directory? */
- if (dta.dta_attribute & 0x10) {
- /* directory: add \*.* to it */
- /* \\ below should be PATH_CHAR */
- strcpy(temp,"\\*.*");
- temp++;
- }
- else {
- /* no wildcards, file exists, not a directory: unique */
- downcase(dta.dta_name);
- add_file(&dta);
- goto gotfiles;
- }
- }
-
- /* do the Fsfirst again because buf may have changed */
- if ((e = Fsfirst(buf,-1)) < 0) {
- printf("%s: %s\r\n",buf,syserr(e));
- goto reallydone;
- }
-
- do {
- /* add the file to the list of files */
- /* add all files if aflag, else skip those with leading dots */
- if (aflag || *(dta.dta_name) != '.') {
- downcase(dta.dta_name);
- add_file(&dta);
- }
- } while (Fsnext() == 0);
-
- if (nfiles == 0) {
- printf("no files\r\n");
- goto reallydone;
- }
-
- gotfiles:
- showlist(0); /* uses globals dtas, nfiles, tflag, lflag, etc. */
-
- if (rflag) {
- /* Do another Fsfirst/Fsnext pass for directories. */
- /* Remember, buf has the Fsfirst target. */
- /* Set temp just past the last PATH_CHAR or DIR_CHAR. */
-
- if ((temp = strrchr(buf,PATH_CHAR)) == NULL) temp = buf;
- else temp++;
-
- if ((p = strrchr(temp,DRV_CHAR)) != NULL) temp = p+1;
-
- if (Fsfirst(buf,-1) < 0) goto reallydone;
- do {
- if ((dta.dta_attribute & 0x10) &&
- (!is_dots(dta.dta_name))) {
- strcpy(temp,dta.dta_name);
- downcase(buf);
- printf("\r\n%s:\r\n",buf);
- do_dir(buf);
- }
- } while (!Fsnext());
- }
-
- reallydone:
- (void)Fsetdta(odta);
- }
-
- void
- top_level(const char **names)
- {
- long e;
- struct _dta dta;
-
- Fsetdta(&dta);
-
- /* call add_file for each name if Fsfirst on it succeeds */
- while (*names) {
- if (is_root(*names)) {
- /* pretend to succeed on d: and d:\ but do nothing */
- }
- else if ((e = Fsfirst(*names,-1)) < 0) {
- printf("%s: %s\r\n",*names,syserr(e));
- *names = NULL;
- }
- else {
- add_named_file(&dta,*names);
- if (!(dta.dta_attribute & 0x10)) *names = NULL;
- }
- ++names;
- }
- showlist(1);
- }
-
- int
- main(int argc,char *argv[])
- {
- char *p;
- int many;
- char *dot = ".";
-
- --argc, ++argv;
- while (*argv && **argv == '-') {
- p = &argv[0][1];
- while (*p) {
- switch (*p) {
- case 'l': lflag++; break; /* more is better */
- case 'F': fflag = 1; break;
- case 'a': aflag = 1; break;
- case 'R': rflag = 1; break;
- case 't': tflag = 1; break;
- case 'd': dflag = 1; break;
- default:
- printf("Unknown option: %c\r\n",*p);
- printf("Usage: ls [-adFlRt] [files ...]\r\n");
- printf("A second -l gives time and date in absolute form\r\n");
- exit(1);
- }
- p++;
- }
- argc--, argv++;
- }
-
- if (!argc) {
- argc = 1;
- argv = ˙
- }
-
- /* if lflag, figure out when "too long ago" is */
- if (lflag) {
- unsigned short now = Tgetdate();
- unsigned short thisyear = (now >> 9);
- unsigned short thismonth = (now >> 5) & 0xf;
- if (thismonth >= 8) {
- thismonth -= 8;
- }
- else {
- thismonth += 4;
- thisyear -= 1;
- }
- too_long_ago = (thisyear << 9) | (thismonth << 5);
- }
-
- /*
- * Do a top-level 'ls' on all the args, if you gave more than one.
- * top_level zeros those argv ptrs which refer to files, not directories.
- *
- * Do this also if dflag, and in addition don't call do_dir.
- */
-
- if (argc > 1 || dflag) {
- many = 1;
- top_level((char **)argv);
- if (dflag) exit(0);
- }
- else many = 0;
-
- while (argc) {
- if (*argv) {
- if (many) {
- printf("\r\n%s:\r\n",*argv);
- }
- do_dir(*argv);
- }
- argv++, argc--;
- }
- exit(0);
- }
-
-